﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace The_LarX
{
    public class TextScript : Component
    {
        private char Separador_Espaco = " ".ToCharArray()[0];

        public List<string> ScriptLines;

        public TextScript(List<string> ScriptLine, GameScreen Screen)
            : base(Screen)
        {
            this.ScriptLines = ScriptLine;
        }
        public TextScript(List<string> ScriptLine)
        {
            this.ScriptLines = ScriptLine;

            CleanScript();
            Run();
        }
        private void CleanScript()
        {
            for (int i = 0; i < ScriptLines.Count; i++)
            {
                if (ScriptLines[i].Contains("\t"))
                {
                    ScriptLines[i] = ScriptLines[i].Replace("\t", "");
                }
            }
        }

        private void Load()
        {
            ScriptLines = new List<string>();
        }

        private bool ExecuteAllTime = false;

        public override void Update()
        {
            base.Update();

            if (ExecuteAllTime)
            {
                Run();
            }
        }

        private string Script_Name;
        private TextScript_VariableCollection Script_Variables;

        private bool script_Initialized;
        private int script_ScriptStartLine;
        private int script_ScriptEndLine;

        private bool script_LoadedVariables;

        private int script_VariablesStartLine;
        private int script_VariablesEndLine;
        private bool script_VariablesFound;
        
        public void Run()
        {
            Script_Variables = new TextScript_VariableCollection();

            if (!script_Initialized)
            {
                InitializeScript();
            }
            if (!script_LoadedVariables)
            {
                InitializeVariables();
            }
            try
            {
                RunMethods();
            }
            catch { }
        }

        private void InitializeScript()
        {
            for (int i = 0; i < ScriptLines.Count; i++)
            {
                if (ScriptLines[i].Contains("Script"))
                {
                    string[] divided = ScriptLines[i].Split(Separador_Espaco);
                    if (divided.Length > 1)
                    {
                        Script_Name = divided[1];
                        script_ScriptStartLine = i + 1;
                        for (int j = 0; j < ScriptLines.Count; j++)
                        {
                            if (ScriptLines[j].Contains("}"))
                            {
                                script_ScriptEndLine = j;
                                script_Initialized = true;
                            }
                        }
                    }
                }
            }
        }
        private void InitializeVariables()
        {
            for (int i = 0; i < ScriptLines.Count; i++)
            {
                if (ScriptLines[i].Contains("Variables"))
                {
                    script_VariablesStartLine = i + 1;
                    for (int j = 0; j < ScriptLines.Count; j++)
                    {
                        if (ScriptLines[j].Contains("}"))
                        {
                            script_VariablesEndLine = j;
                            j = ScriptLines.Count;
                            script_VariablesFound = true;
                        }
                    }
                    i = ScriptLines.Count;
                }
            }
            if (script_VariablesFound)
            {
                if (script_VariablesEndLine - script_VariablesStartLine > 1)
                {
                    for (int i = script_VariablesStartLine + 1; i < script_VariablesEndLine; i++)
                    {
                        List<string> divided = ScriptLines[i].Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();

                        if (divided.Count > 0)
                        {
                            if (divided[0].ToLower() == "float")
                            {
                                float NoName = float.Parse(divided[3]);
                                string floatName = divided[1];
                                TextScript_Variable var = new TextScript_Variable(NoName, floatName);
                                this.Script_Variables.Add(var);
                            }
                            if (divided[0].ToLower() == "int")
                            {
                                int NoName = int.Parse(divided[3]);
                                string intName = divided[1];
                                TextScript_Variable var = new TextScript_Variable(NoName, intName);
                                this.Script_Variables.Add(var);
                            }
                        }
                    }
                    script_LoadedVariables = true;
                }
            }
        }

        private void RunMethods()
        {
            for (int i = 0; i < ScriptLines.Count; i++)
            {
                if (ScriptLines[i].Contains("Method"))
                {
                    List<string> divided = ScriptLines[i].Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();
                    string methodName = divided[1];
                    int methodStartLine = i + 1;
                    int methodEndLine = 0;
                    for (int j = methodStartLine; j < ScriptLines.Count; j++)
                    {
                        if (ScriptLines[j].Contains("}"))
                        {
                            methodEndLine = j;
                            j = ScriptLines.Count;
                        }
                    }

                    for (int k = methodStartLine + 1; k < methodEndLine; k++)
                    {
                        List<string> methodLine = ScriptLines[k].Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();

                        if (methodLine[0] == "if")
                        {
                        }
                        else
                        {
                            // if it isn't any of other cases, should be an equality
                            object obj1 = GetObjectByName(methodLine[0]);
                            object obj11;
                            PropertyInfo baseProp;
                            PropertyInfo Info1 = GetPropertyByName(methodLine[0], obj1.GetType(), out obj11, obj1, out baseProp);
                            if (methodLine[1] == "=")
                            {
                                object obj2 = GetObjectByName(methodLine[2]);
                                object obj22;
                                PropertyInfo baseProp2;
                                PropertyInfo Info2 = GetPropertyByName(methodLine[2], obj2.GetType(), out obj22, obj2, out baseProp2);
                                if (obj11 != null && obj22 == null)
                                {
                                    object value = Info2.GetValue(obj2, null);
                                    Info1.SetValue(obj11, value, null);
                                    baseProp.SetValue(obj1, obj11, null);
                                }
                                if (obj11 != null && obj22 != null)
                                {
                                    object value = Info2.GetValue(obj22, null);
                                    Info1.SetValue(obj11, value, null);
                                    baseProp.SetValue(obj1, obj11, null);
                                }
                                if (obj11 == null && obj22 != null)
                                {
                                    object value = Info2.GetValue(obj22, null);
                                    Info1.SetValue(obj1, value, null);
                                }
                                if (obj11 == null && obj22 == null)
                                {
                                    Info1.SetValue(obj1, Info2.GetValue(obj2, null), null);
                                }
                            }
                            if (methodLine[1] == "+=")
                            {
                            }
                        }
                    }
                }
            }
        }

        private static PropertyInfo GetPropertyByName(string Name, Type objectType, out object BaseObjectProperty, object BaseObject, out PropertyInfo BaseObjectInfo)
        {
            string[] vars = Name.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            if (vars.Length > 2)
            {
                if (vars.Length > 3)
                {
                    string PropertyName = vars[2];
                    PropertyInfo info = objectType.GetProperty(PropertyName);
                    BaseObjectInfo = info;
                    BaseObjectProperty = info.GetValue(BaseObject, null);
                    Type propertyType = info.PropertyType;
                    string ThirdPropertyName = vars[3];
                    return propertyType.GetProperty(ThirdPropertyName);
                }
                else
                {
                    string PropertyName = vars[2];
                    BaseObjectProperty = null;
                    BaseObjectInfo = null;
                    return objectType.GetProperty(PropertyName);
                }
            }
            else
            {
                if (objectType == typeof(TextScript_Variable))
                {
                    BaseObjectProperty = null;
                    BaseObjectInfo = null;
                    return objectType.GetProperty("Object");                    
                }
            }
            BaseObjectProperty = null;
            BaseObjectInfo = null;
            return null;
        }
        private object GetObjectByName(string Name)
        {
            if (Name.ToLower().StartsWith("actors."))
            {
                string[] actorVars = Name.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                string ActorName = actorVars[1];
                if (EngineSystem.Actor_ByName(ActorName) != null)
                {
                    Actor actor = EngineSystem.Actor_ByName(ActorName);
                    return actor;
                }                
            }
            if (Name.ToLower().StartsWith("components."))
            {
                string[] componentVars = Name.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                string ComponentName = componentVars[1];
                foreach (GameScreen screen in Engine.GameScreens)
                {
                    if (screen.Components.Contains(ComponentName))
                    {
                        Component comp = screen.Components[ComponentName];
                        return comp;
                    }
                }
            }
            if (Name.ToLower().StartsWith("var."))
            {
                string[] actorVars = Name.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                string ActorName = actorVars[1];
                if (Script_Variables.Contains(ActorName))
                {
                    TextScript_Variable actor = Script_Variables[ActorName];
                    return actor.Object;
                }
            }            
            return null;
        }
    }
}
